﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;


namespace UtilityToolsCollect.ExtensionMethodLibrary
{
    public static class StringEX
    {
        public static byte[] ToBytes(this string Source, int fromBase, bool WithSeparator = false)
        {
            string[] Split(int value)
            {
                if (Source.Length % value != 0) throw new FormatException("长度错误");
                string[] Result = new string[Source.Length / value];
                Span<char> s = Source.ToCharArray();
                int index = 0;
                for (int i = 0; i < s.Length; i += value)
                    Result[index++] = new string(s.Slice(i, value).ToArray());
                return Result;
            }

            return WithSeparator ?
              Array.ConvertAll(Source.Split('-'), (p) => Convert.ToByte(p, fromBase)) :
              fromBase switch
              {
                  2 => Array.ConvertAll(Split(8), (p) => Convert.ToByte(p, 2)),
                  16 => Array.ConvertAll(Split(2), (p) => Convert.ToByte(p, 16)),
                  _ => throw new NotImplementedException("不支持的功能"),
              };
        }
        public static bool Contains(this string source, string value, StringComparison comparison = StringComparison.OrdinalIgnoreCase) => source.IndexOf(value, comparison) >= 0;
        public enum CharComparison { Ordinal , OrdinalIgnoreCase , InvariantCultureIgnoreCase , CurrentCultureIgnoreCase }

        public static char ToLowerOrdinal(this char value)
        {
            if ((value > 64) && (value < 91))
                return (char)(value + 32);
            return value;
        }

        public static char ToUpperOrdinal(this char value)
        {
            if ((value > 96) && (value < 123))
                return (char)(value - 32);
            return value;
        }

        public static bool CharEquals(this char source,char value, CharComparison comparisonType = CharComparison.Ordinal)
        {
            if (comparisonType < CharComparison.Ordinal || comparisonType > CharComparison.CurrentCultureIgnoreCase)
                throw new ArgumentException("CharComparison枚举中不存在指定的类型", "comparisonType");

            switch (comparisonType)
            {
                case CharComparison.CurrentCultureIgnoreCase:
                    return char.ToLower(source) == char.ToLower(value);

                case CharComparison.InvariantCultureIgnoreCase:
                    return char.ToLowerInvariant(source) == char.ToLowerInvariant(value);

                case CharComparison.OrdinalIgnoreCase:
                    return ToLowerOrdinal(source) == ToLowerOrdinal(value);

                default:
                    return source == value;
            }
        }

        public static bool CharEquals(this char? source, char? value, CharComparison comparisonType = CharComparison.Ordinal)
        {
            bool IsSourceNull = source == null;
            bool IsValueNull = value == null;

            if (IsSourceNull && IsValueNull)
                return true;

            if (IsSourceNull || IsValueNull)
                return false;

            return CharEquals((char)source!, (char)value!, comparisonType);
        }

        public static bool IsFirstCharEquals(this string source, char value, CharComparison comparisonType = CharComparison.Ordinal)
        {
            if (string.IsNullOrEmpty(source))
                return false;
            return source[0].CharEquals(value,comparisonType);
        }

        public static bool IsFirstCharEquals(this string source, char? value, CharComparison comparisonType = CharComparison.Ordinal)
        {
            char? m_source = string.IsNullOrEmpty(source) ? new char?() : source[0];
            return m_source.CharEquals(value, comparisonType);
        }

        public static bool IsLastCharEquals(this string source, char value, CharComparison comparisonType = CharComparison.Ordinal)
        {
            if (string.IsNullOrEmpty(source))
                return false;
            return source[source.Length - 1].CharEquals(value, comparisonType);
        }

        public static bool IsLastCharEquals(this string source, char? value, CharComparison comparisonType = CharComparison.Ordinal)
        {
            char? m_source = string.IsNullOrEmpty(source) ? new char?() : source[source.Length - 1];
            return m_source.CharEquals(value, comparisonType);
        }

        public static bool Exists(this string[] Source, string value, out int Index, StringComparison comparison = StringComparison.OrdinalIgnoreCase)
        {
            for (int i = 0; i < Source.Length; i++)
            {
                if (Source[i].Equals(value, comparison))
                {
                    Index = i;
                    return true;
                }
            }
            Index = -1;
            return false;
        }


        /// <summary>
        /// 参数字符串分割，用以识别有""号包涵起来的路径，智能分割字符串，在""号内部的字符串不参与分割
        /// </summary>
        /// <param name="ArgString"></param>
        /// <returns></returns>
        public static string[] ArgStringSplit(this string ArgString)
        {
            if (string.IsNullOrWhiteSpace(ArgString)) throw new ArgumentNullException("参数为空，该函数不接受空参数");
            char[] ArgChars = ArgString.Trim().ToCharArray();
            bool skip = false;
            for (int i = 0; i < ArgChars.Length; i++)
            {
                if (ArgChars[i] == '\"') skip = !skip;
                if (skip) continue;
                if (ArgChars[i] == ' ') ArgChars[i] = '\n';
            }
            return new string(ArgChars).Split('\n');
        }

        public static string[] StringIndexSplit(this string m_String, int SplitIndex, bool SkipIndexChar = false)
        {
            if (SkipIndexChar)
                return new string[] { m_String.Substring(0, SplitIndex), m_String.Substring(SplitIndex + 1) };
            return new string[] { m_String.Substring(0, SplitIndex), m_String.Substring(SplitIndex) };
        }


        /// <summary>
        /// 将一组数字字符串（10进制内存表现形式（byte）的）转换为(int)文字字符串
        /// </summary>
        /// <param name="numbers"></param>
        /// <returns></returns>
        public static string ByteStringToIntString(string numbers)
        {
            string[] sa = numbers.Split('_');
            string[] sb = new string[sa.Length - 1];
            System.Array.Copy(sa, 0, sb, 0, sa.Length - 1);

            return System.Text.Encoding.UTF8.GetString(
            System.Array.ConvertAll(sb, p => (byte)int.Parse(p)));
        }

        /// <summary>
        /// 将一组(int)文字字符串转换为一组（10进制内存表现形式（byte）的）数字字符串
        /// </summary>
        /// <param name="srt"></param>
        /// <returns></returns>
        public static string IntStringToByteString(string srt)
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder();

            foreach (int sz in System.Array.ConvertAll(System.Text.Encoding.UTF8.GetBytes(srt), p => ((int)p)))
            {
                sb.Append(sz.ToString() + "_");
            }
            return sb.ToString();
        }


        /// <summary>
        /// char转换汉子数字
        /// </summary>
        public static long CharToNumber(char c)
        {
            switch (c)
            {
                case '一': return 1;
                case '二': return 2;
                case '三': return 3;
                case '四': return 4;
                case '五': return 5;
                case '六': return 6;
                case '七': return 7;
                case '八': return 8;
                case '九': return 9;
                case '零': return 0;
                default: return -1;
            }
        }

        /// <summary>
        /// char转换汉子数字单位
        /// </summary>
        public static long CharToUnit(char c)
        {
            switch (c)
            {
                case '十': return 10;
                case '百': return 100;
                case '千': return 1000;
                case '万': return 10000;
                case '亿': return 100000000;
                default: return 1;
            }
        }

        /// <summary>
        /// 将中文数字转换阿拉伯数字
        /// </summary>
        /// <param name="cnum">汉字数字</param>
        /// <returns>长整型阿拉伯数字</returns>
        public static long ParseCnToInt(string cnum)
        {
            cnum = Regex.Replace(cnum, "\\s+", "");
            long firstUnit = 1;//一级单位
            long secondUnit = 1;//二级单位
            long result = 0;//结果
            for (var i = cnum.Length - 1; i > -1; --i)//从低到高位依次处理
            {
                var tmpUnit = CharToUnit(cnum[i]);//临时单位变量
                if (tmpUnit > firstUnit)//判断此位是数字还是单位
                {
                    firstUnit = tmpUnit;//是的话就赋值,以备下次循环使用
                    secondUnit = 1;
                    if (i == 0)//处理如果是"十","十一"这样的开头的
                    {
                        result += firstUnit * secondUnit;
                    }
                    continue;//结束本次循环
                }
                if (tmpUnit > secondUnit)
                {
                    secondUnit = tmpUnit;
                    continue;
                }
                result += firstUnit * secondUnit * CharToNumber(cnum[i]);//如果是数字,则和单位想乘然后存到结果里
            }
            return result;
        }

        /// <summary>
        /// 阿拉伯数字转换成中文数字
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public static string NumStringToChineseString(string x)
        {
            string[] pArrayNum = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" };
            //为数字位数建立一个位数组
            string[] pArrayDigit = { "", "十", "百", "千" };
            //为数字单位建立一个单位数组
            string[] pArrayUnits = { "", "万", "亿", "万亿" };
            var pStrReturnValue = ""; //返回值
            var finger = 0; //字符位置指针
            var pIntM = x.Length % 4; //取模
            int pIntK;
            if (pIntM > 0)
                pIntK = x.Length / 4 + 1;
            else
                pIntK = x.Length / 4;
            //外层循环,四位一组,每组最后加上单位: ",万亿,",",亿,",",万,"
            for (var i = pIntK; i > 0; i--)
            {
                var pIntL = 4;
                if (i == pIntK && pIntM != 0)
                    pIntL = pIntM;
                //得到一组四位数
                var four = x.Substring(finger, pIntL);
                var P_int_l = four.Length;
                //内层循环在该组中的每一位数上循环
                for (int j = 0; j < P_int_l; j++)
                {
                    //处理组中的每一位数加上所在的位
                    int n = Convert.ToInt32(four.Substring(j, 1));
                    if (n == 0)
                    {
                        if (j < P_int_l - 1 && Convert.ToInt32(four.Substring(j + 1, 1)) > 0 && !pStrReturnValue.EndsWith(pArrayNum[n]))
                            pStrReturnValue += pArrayNum[n];
                    }
                    else
                    {
                        if (!(n == 1 && (pStrReturnValue.EndsWith(pArrayNum[0]) | pStrReturnValue.Length == 0) && j == P_int_l - 2))
                            pStrReturnValue += pArrayNum[n];
                        pStrReturnValue += pArrayDigit[P_int_l - j - 1];
                    }
                }
                finger += pIntL;
                //每组最后加上一个单位:",万,",",亿," 等
                if (i < pIntK) //如果不是最高位的一组
                {
                    if (Convert.ToInt32(four) != 0)
                        //如果所有4位不全是0则加上单位",万,",",亿,"等
                        pStrReturnValue += pArrayUnits[i - 1];
                }
                else
                {
                    //处理最高位的一组,最后必须加上单位
                    pStrReturnValue += pArrayUnits[i - 1];
                }
            }
            return pStrReturnValue;
        }
    }

    public class SundaySearch
    {
        private static int StringMax(string Value)
        {
            int Result = 255;
            foreach (int value in Value)
                if (value > Result) Result = value;
            return Result;
        }
        private static int[] GetSundayBuffer(string Source, string Pattern, int PatternLength)
        {
            if (string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(Pattern))
                return new int[0];
            int[] buffer = new int[Math.Max(StringMax(Pattern) + 1, StringMax(Source) + 1)];
            // 默认值，移动m+1位
            buffer.Fill(Pattern.Length + 1);

            // 模式串P中每个字母出现的最后的下标
            // 所对应的主串参与匹配的最末位字符的下一位字符移动到该位，所需要的移动位数
            for (int i = 0; i < PatternLength; i++)
                buffer[Pattern[i]] = PatternLength - i;
            return buffer;
        }
        private static int SundayIndexOf(string Source, string Pattern, int[] SundayBuffer, int StartPosition = 0)
        {
            if (string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(Pattern))
                return -1;
            int SourceLength = Source.Length;
            int PatternLength = Pattern.Length;

            // 模式串开始位置在主串的哪里
            int Start = StartPosition;
            // 模式串已经匹配到的位置
            int Current, SPSum;

            while (Start <= SourceLength - PatternLength)
            {
                Current = 0;
                while (Source[Start + Current] == Pattern[Current])
                {
                    Current++;
                    // 匹配成功
                    if (Current >= PatternLength)
                        return Start;
                }
                // 找到主串中当前跟模式串匹配的最末字符的下一个字符
                // 在模式串中出现最后的位置
                // 所需要从(模式串末尾+1)移动到该位置的步数
                SPSum = Start + PatternLength;
                if (SPSum >= SourceLength)
                    break;
                Start += SundayBuffer[Source[SPSum]];
            }
            return -1;
        }
        public static bool SundayIndexOf(string Source, string Pattern, out int Result, int[] SundayBuffer, int StartPosition = 0) => (Result = SundayIndexOf(Source, Pattern, SundayBuffer, StartPosition)) > -1;
        public static bool SundayIndexOf(string Source, string Pattern, out int Result, int StartPosition = 0) => SundayIndexOf(Source, Pattern, out Result, GetSundayBuffer(Source, Pattern, Pattern.Length), StartPosition);
        //public static bool SundayIndexOf(string Source, string Pattern, out int Result, int[] SundayBuffer, int StartPosition = 0) => SundayIndexOf((ReadOnlySpan<char>)Source, (ReadOnlySpan<char>)Pattern, out Result, (ReadOnlySpan<int>)SundayBuffer, StartPosition);
        public static IEnumerable<int> SundaySearchAllIndexs(string Source, string Pattern, int StartPosition = 0)
        {
            int result;
            if (string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(Pattern))
                yield break;
            int[] Buffer = GetSundayBuffer(Source, Pattern, Pattern.Length);
            while (SundayIndexOf(Source, Pattern, out result, Buffer, StartPosition))
            {
                yield return result;
                StartPosition = result + Pattern.Length;
            }
            yield break;
        }
        
        public static int IndexOF(string Source, string Pattern, int StartPosition = 0)
        {
            int index = 0;                //主要用来记录每一次的匹配位置
            int i = StartPosition;      //每一次新的循环起始位置
            int j = 0, next = 0;            //j用来记录子串的遍历位置,next记录下一个起始位置
            while (i < Source.Length)
            {
                next = i + Pattern.Length;
                index = i;
                j = 0;
                if (Pattern[j] != Source[index])
                {
                    //重新计算i的下一个位置
                    if (next < Source.Length)
                    {
                        int cut = 0;
                        for (int z = 0; z < Pattern.Length; z++)
                        {
                            if (Source[next] == Pattern[z])
                            {
                                cut = z;
                            }
                        }
                        if (cut == 0 && Source[next] != Pattern[0])
                        {
                            next++;
                        }
                        else
                        {
                            next -= cut;
                        }
                    }
                    i = next;
                    continue;
                }
                else
                {
                    while (j < Pattern.Length)
                    {
                        if (Pattern[j] != Source[index])
                        {
                            //重新计算i的下一个位置
                            if (next < Source.Length)
                            {
                                int cut = 0;
                                for (int z = 0; z < Pattern.Length; z++)
                                {
                                    if (Source[next] == Pattern[z])
                                    {
                                        cut = z;
                                    }
                                }
                                if (cut == 0 && Source[next] != Pattern[0])
                                {
                                    next++;
                                }
                                else
                                {
                                    next -= cut;
                                }
                            }
                            i = next;
                            break;
                        }
                        index++;
                        j++;
                    }
                    if (j == Pattern.Length)
                    {
                        break;
                    }
                }
            }

            if (j == Pattern.Length)
            {
                return index - j;
            }

            return -1;
        }
        public static bool IndexOF(string Source, string Pattern, out int Result, int StartPosition = 0) => (Result = IndexOF(Source, Pattern, StartPosition)) > -1;
        public static IEnumerable<int> SearchAllIndexs(string Source, string Pattern, int StartPosition = 0)
        {
            int result;
            while (IndexOF(Source, Pattern, out result, StartPosition))
            {
                yield return result;
                StartPosition = result + Pattern.Length;
            }
            yield break;
        }
    }

}
